home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 March / EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso / earcd / ear / 8n1.lha / 8n1.s < prev    next >
Text File  |  1995-09-19  |  91KB  |  1,934 lines

  1. **  $Revision Header Start *****************************************************
  2. **                                                                            **
  3. **  Name       : 8n1.s                                                        **
  4. **  Copyright  : © Copyright 95                                               **
  5. **  Author     : L.Lucius                                                     **
  6. **  Created    : 10 Jul 95                                                    **
  7. **  Version    : 37.13                                                        **
  8. **  Translator : snma 2.00 17-Sep-95                                          **
  9. **                                                                            **
  10. **  Date       Version  Comment                                               **
  11. **  ---------  -------  ----------------------------------------------------  **
  12. **  19 Sep 95  37.13    Fourth Aminet release.                                **
  13. **  07 Sep 95  37.13    Store flag byte after setting in AbortIO.             **
  14. **  02 Sep 95  37.12    Third Aminet release.                                 **
  15. **  02 Sep 95  37.12    Changed DS alignment directives to CNOP directives.   **
  16. **  29 Aug 95  37.12    Added test for QUICK bit in AbortIO routine.          **
  17. **  29 Aug 95  37.12    Removed PC-Relative optimizer option to prevent       **
  18. **                      incorrect conversion to a 68020+ instruction.  This   **
  19. **                      should fix the problems on 68000 machines.            **
  20. **  27 Aug 95  37.12    Added I/O completion status to each command routine   **
  21. **                      and removed unnecessary code from BeginIO routine.    **
  22. **  27 Aug 95  37.12    Re-added list arbitration in cmd_Read.                **
  23. **  24 Aug 95  37.11    Isolated SNMA directives to allow assembly with       **
  24. **                      SAS/C assembler.                                      **
  25. **  23 Aug 95  37.11    Add code to correct bug in NComm.  Define symbol      **
  26. **                      NCOMM and reassemble to get this support.             **
  27. **  23 Aug 95  37.11    Check SOFTINT prior to TBE to keep 8n1 from blocking  **
  28. **                      them.                                                 **
  29. **  23 Aug 95  37.11    Insure that interrupts are enabled prior to checking  **
  30. **                      TBE or RBF interrupts.                                **
  31. **  22 Aug 95  37.11    Turn Handshake on by default to match SerFlags.       **
  32. **  21 Aug 95  37.11    Use current baud and buffer sizes for initializing    **
  33. **                      I/O request instead of default.                       **
  34. **  21 Aug 95  37.11    Set default SERFLAGS during device open.              **
  35. **  20 Aug 95  37.11    Clear SERB_ACTIVE IO_FLAG when I/O has completed.     **
  36. **  20 Aug 95  37.11    Removed unneeded RTS line code added on 04-Aug-95.    **
  37. **  15 Aug 95  37.11    Added line to turn on the DSR bit if needed.          **
  38. **                      Normally commented out.                               **
  39. **  11 Aug 95  37.10    Second Aminet release!                                **
  40. **  10 Aug 95  37.10    Added storage arbitration code to cmd_Read and        **
  41. **                      sdcmd_SetParams.                                      **
  42. **  09 Aug 95  37.10    Removed CIAF_PRTRSEL from PRTMASK to allow usage of   **
  43. **                      ring indicator line.                                  **
  44. **  06 Aug 95  37.10    Added "E-" to SNMAOPT line to prevent "Xref in        **
  45. **                      executable" message.                                  **
  46. **  06 Aug 95  37.10    Changed "8n1Base" to "Base8n1" to make more           **
  47. **                      compatible with other assemblers.                     **
  48. **  06 Aug 95  37.10    Removed ".w" from BTST instructions.                  **
  49. **  06 Aug 95  37.10    Corrected long word test of byte sized field.         **
  50. **  04 Aug 95  37.9     First Aminet Release!                                 **
  51. **  04 Aug 95  37.9     Removed some testing code and prevented unnecessary   **
  52. **                      RTS line updates.                                     **
  53. **  02 Aug 95  37.8     Added the ability to send BREAKs.                     **
  54. **  29 Jul 95  37.7     Rearranged device init data to allow proper display   **
  55. **                      by VERSION command.  (The device base init data had   **
  56. **                      to be within the checksummed area.)                   **
  57. **  28 Jul 95  37.6     When device was opened multiple times in shared       **
  58. **                      mode, GURU occured on first close.                    **
  59. **  22 Jul 95  37.5     Corrected version number.  8n1.i was not being        **
  60. **                      generated correctly.                                  **
  61. **  22 Jul 95  37.5     Incorrect handling of interrupts caused TBE           **
  62. **                      interrupts to be missed.                              **
  63. **  13 Jul 95  37.4     Rewrote the CMD_WRITE and TBE interrupt routines.     **
  64. **                      Lengths of -1 were not being handled properly.        **
  65. **  13 Jul 95  37.3     Rewrote OpenDevice() and CloseDevice() calls to       **
  66. **                      correct several problems.                             **
  67. **  11 Jul 95  37.2     Added "no handshaking" support.                       **
  68. **  11 Jul 95  37.1     Rewrote the RBF interrupt routines and offloaded      **
  69. **                      some of the work to a PORTS interrupt to prevent      **
  70. **                      overruns and add the EOFMODE option.                  **
  71. **  07 Jul 95  37.0     Only tried to remove the 'serial.device' instead of   **
  72. **                      removing the CURRENT owner of the serial resources.   **
  73. **  06 Jul 95  37.0     Invalid size used for GetPrefs() call causing stack   **
  74. **                      overlay.                                              **
  75. **  04 Jul 95  37.0     Set defaults during OpenDevice() instead of assuming  **
  76. **                      values in I/O request are correct.                    **
  77. **  04 Jul 95  37.0     Initial Version                                       **
  78. **                                                                            **
  79. **  $Revision Header End *******************************************************
  80.          ;
  81.          ;        SNMA specific options
  82.          ;
  83.          IFD      SNMA
  84.          ;
  85.          CPU      M68010
  86.          ;
  87.          SNMAOPT  Q,A,M,T,E-
  88.          ;
  89.          INCDIR   "include:"
  90.          ;
  91.          ENDC
  92.          ;
  93.          ;
  94.          ;
  95. DEBUG    SET      0
  96.          ;
  97.          ;
  98.          ;
  99.          SECTION  text,CODE
  100.          ;
  101.          ;
  102.          ;
  103. DEVICES_SERIAL_I_OBSOLETE  EQU      1
  104.          ;
  105.          ;
  106.          ;
  107.          INCLUDE  "exec/lists.i"
  108.          INCLUDE  "exec/memory.i"
  109.          INCLUDE  "exec/resident.i"
  110.          INCLUDE  "exec/devices.i"
  111.          INCLUDE  "exec/execbase.i"
  112.          INCLUDE  "exec/io.i"
  113.          INCLUDE  "exec/ports.i"
  114.          INCLUDE  "exec/errors.i"
  115.          INCLUDE  "exec/initializers.i"
  116.          INCLUDE  "intuition/preferences.i"
  117.          INCLUDE  "devices/timer.i"
  118.          INCLUDE  "devices/serial.i"
  119.          INCLUDE  "hardware/custom.i"
  120.          INCLUDE  "hardware/cia.i"
  121.          INCLUDE  "hardware/intbits.i"
  122.          INCLUDE  "hardware/adkbits.i"
  123.          INCLUDE  "resources/misc.i"
  124.          INCLUDE  "exec/alerts.i"
  125.          INCLUDE  "exec/macros.i"
  126.          INCLUDE  "8n1.i"
  127.          ;
  128.          ;        Define hardware references
  129.          ;
  130.          XREF     _AbsExecBase
  131.          XREF     _custom
  132.          XREF     _intena,_intenar,_intreq,_intreqr
  133.          XREF     _ciab,_ciabpra
  134.          XREF     _serper,_serdat,_serdatr
  135.          XREF     _adkcon,_adkconr
  136.          ;
  137.          ;        Exec Functions
  138.          ;
  139.          XREF     _LVORemDevice,_LVOOpenDevice,_LVOCloseDevice
  140.          XREF     _LVOSupervisor
  141.          XREF     _LVORemove,_LVORemHead,_LVOAddTail
  142.          XREF     _LVOAllocMem,_LVOFreeMem,_LVOCopyMem
  143.          XREF     _LVOReplyMsg
  144.          XREF     _LVOSendIO,_LVOAbortIO
  145.          XREF     _LVODisable,_LVOEnable
  146.          XREF     _LVOFindName
  147.          XREF     _LVOOpenResource
  148.          XREF     _LVOAddIntServer,_LVORemIntServer
  149.          XREF     _LVOSetIntVector
  150.          XREF     _LVOAlert
  151.          XREF     _LVOOldOpenLibrary,_LVOCloseLibrary
  152.          ;
  153.          ;        Misc Resource Functions
  154.          ;
  155.          XREF     _LVOAllocMiscResource,_LVOFreeMiscResource
  156.          ;
  157.          ;        Intuition Functions
  158.          ;
  159.          XREF     _LVOGetPrefs
  160.          ;
  161.          ;        Mask used to get rid of the printer bits.
  162.          ;
  163. PRTMASK  EQU      (CIAF_PRTRPOUT|CIAF_PRTRBUSY)
  164.          ;
  165.          ;        Autovector offsets
  166.          ;
  167. LVL1VEC  EQU      (1-1)*4+$64
  168. LVL5VEC  EQU      (5-1)*4+$64
  169.          ;
  170.          ;        Device base
  171.          ;
  172.          STRUCTURE Base8n1,LIB_SIZE
  173.          UBYTE    vb_SaveDDRA
  174.          UBYTE    vb_SavePRA
  175.          APTR     vb_MiscBase
  176.          APTR     vb_OldLevel1
  177.          APTR     vb_OldLevel5
  178.          ULONG    vb_SegList
  179.          ULONG    vb_DefBaud
  180.          ULONG    vb_DefRBufLen
  181.          ULONG    vb_CurRBuf
  182.          ULONG    vb_CurRBufLen
  183.          ULONG    vb_CurBaud
  184.          UBYTE    vb_SerFlags
  185.          UBYTE    vb_Initialized
  186.          LABEL    sizeof_Base8n1
  187.          ;
  188.          ;
  189.          ;
  190. DISABLE  MACRO
  191.          IFNC     '\1',''
  192.          move.w   #INTF_\1,_intena
  193.          ELSE
  194.          jsr      _LVODisable(a6)
  195.          ENDC
  196.          ENDM
  197.          ;
  198. ENABLE   MACRO
  199.          IFNC     '\1',''
  200.          move.w   #INTF_SETCLR|INTF_\1,_intena
  201.          ELSE
  202.          jsr      _LVOEnable(a6)
  203.          ENDC
  204.          ENDM
  205.          ;
  206.          ;
  207.          ;
  208. PUTDEBUG macro    ;[msg]
  209.          ifge     DEBUG-2
  210.          movem.l  a0/a1/d0/d1,-(sp)
  211.          lea      (.msg\@,pc),a0  ;Point to static format string
  212.          lea      (4*4,sp),a1     ;Point to args
  213.          XREF     DPutFmt
  214.          bsr      DPutFmt
  215.          movem.l  (sp)+,d0/d1/a0/a1
  216.          bra.b    .end\@
  217.  
  218. .msg\@   dc.b     \1,10,0
  219.          CNUL     0,4
  220. .end\@
  221.          endc
  222.          endm
  223.          ;
  224.          ;
  225.          ;
  226. DEBUG1   MACRO
  227.          IFEQ      DEBUG-1
  228.          XREF     _SendText
  229.          move.l   \2,-(sp)
  230.          pea.l    debug1s\@$
  231.          pea.l    Name
  232.          jsr      _SendText(pc)
  233.          lea.l    12(sp),sp
  234.          bra.b    debug1x\@$
  235. debug1s\@$:
  236.          dc.b     \1,0
  237.          CNOP     0,2
  238. debug1x\@$:
  239.          ENDC
  240.          ENDM
  241. DEBUG0   MACRO
  242.          XREF     _SendText
  243.          pea.l    debug1s\@$
  244.          pea.l    Name
  245.          jsr      _SendText(pc)
  246.          lea.l    8(sp),sp
  247.          bra.b    debug1x\@$
  248. debug1s\@$:
  249.          dc.b     \1,0
  250. debug1x\@$:
  251.          ENDM
  252.  
  253. DEBUGIO  MACRO
  254.          IFEQ     DEBUG-1
  255.          lea.l    \1,a0
  256.          jsr      printIO
  257.          ENDC
  258.          ENDM
  259.          ;
  260.          ;
  261.          ;
  262. Start:
  263.          moveq    #-1,d0                              ; set return code
  264.          rts                                          ; return
  265.          ;
  266.          ;        RamLib looks for this romtag
  267.          ;
  268. ROMTag   DC.W     RTC_MATCHWORD                       ; RT_MATCHWORD
  269.          DC.L     ROMTag                              ; RT_MATCHTAG
  270.          DC.L     ENDTag                              ; RT_ENDSKIP
  271.          DC.B     RTF_AUTOINIT                        ; RT_FLAGS
  272.          DC.B     VERSION                             ; RT_VERSION
  273.          DC.B     NT_DEVICE                           ; RT_TYPE
  274.          DC.B     0                                   ; RT_PRI
  275.          DC.L     Name                                ; RT_NAME
  276.          DC.L     IdString                            ; RT_IDSTRING
  277.          DC.L     Init                                ; RT_INIT
  278.          ;
  279.          ;        Perform device initialization
  280.          ;
  281. InitRoutine:
  282.          exg      d0,a0                               ; swap seglist and base
  283.          move.l   d0,vb_SegList(a0)                   ; store seglist in base
  284.          move.l   a6,SysBase                          ; store in global storage
  285.          exg      a0,d0                               ; swap them back
  286.          rts                                          ; return
  287.          ;
  288.          ;
  289.          ;
  290. dev_Open:
  291.          DEBUG1   "Devstart %lx",#Start
  292.          move.l   a5,-(sp)                            ; save registers
  293.          movea.l  a6,a5                               ; save base
  294.          movea.l  SysBase(pc),a6                      ; get ExecBase
  295.          ;
  296.          tst.l    d0                                  ; unit 0 specified?
  297.          bne.b    50$                                 ; nope, error (who cares?)
  298.          ;
  299.          tst.w    LIB_OPENCNT(a5)                     ; currently open?
  300.          bne.b    10$                                 ; yep, go process
  301.          ;
  302.          move.b   IO_SERFLAGS(a1),vb_SerFlags(a5)     ; save flags
  303.          ;
  304.          tst.b    vb_Initialized(a5)                  ; already initialized?
  305.          bne.b    40$                                 ; yep, skip initialization
  306.          ;
  307.          bsr      initResources                       ; go alloc resources
  308.          tst.l    d0                                  ; initialized?
  309.          bne.b    50$                                 ; nope, error
  310.          ;
  311.          bra.b    40$                                 ; go exit
  312.          ;
  313. 10$      moveq    #SerErr_DevBusy,d0                  ; preset error status
  314.          btst.b   #SERB_SHARED,vb_SerFlags(a5)        ; opened shared?
  315.          beq.b    50$                                 ; nope, error
  316.          btst.b   #SERB_SHARED,IO_SERFLAGS(a1)        ; requesting shared?
  317.          beq.b    50$                                 ; nope, error
  318.          ;
  319.          ;        Initialize I/O request
  320.          ;
  321. 40$      moveq    #8,d0                               ; get char size
  322.          move.b   d0,IO_READLEN(a1)                   ; set read length
  323.          move.b   d0,IO_WRITELEN(a1)                  ; set write length
  324.          moveq    #1,d0                               ; get stop bits
  325.          move.b   d0,IO_STOPBITS(a1)                  ; set stop bits
  326.          ori.b    #SERF_XDISABLED|SERF_RAD_BOOGIE|SERF_QUEUEDBRK|SERF_7WIRE,IO_SERFLAGS(a1) ;flags
  327.          andi.b   #~(SERF_PARTY_ODD|SERF_PARTY_ON),IO_SERFLAGS(a1) ; not used
  328.          move.l   vb_CurBaud(a5),IO_BAUD(a1)          ; set baud
  329.          move.l   vb_CurRBufLen(a5),IO_RBUFLEN(a1)    ; set read buffer length
  330.          ;
  331.          addq.w   #1,LIB_OPENCNT(a5)                  ; incr open count
  332.          bclr.b   #LIBB_DELEXP,LIB_FLAGS(a5)          ; clear expunge bit
  333.          moveq    #0,d0                               ; no error
  334.          ;
  335. 50$      move.b   d0,IO_ERROR(a1)                     ; store error code
  336.          movea.l  a5,a6                               ; restore base
  337.          move.l   (sp)+,a5                            ; restore registers
  338.          rts                                          ; return
  339.          ;
  340.          ;        Attempt to allocate one of the serial resources.
  341.          ;
  342. allocResource:
  343.          move.l   a6,-(sp)                            ; save base pointer
  344.          move.l   d0,-(sp)                            ; save unit
  345.          lea.l    Name(pc),a1                         ; get lock name
  346.          move.l   vb_MiscBase(a5),a6                  ; get MiscBase
  347.          jsr      _LVOAllocMiscResource(a6)           ; go allocate it
  348.          tst.l    d0                                  ; did we get it?
  349.          beq.b    20$                                 ; yep, branch
  350.          ;
  351.          ;        It's in use, so we try to locate the device using the string
  352.          ;        returned and attempt to remove it.
  353.          ;
  354.          movea.l  SysBase(pc),a6                      ; get ExecBase
  355.          ;
  356.          movea.l  d0,a1                               ; get ptr to serial name
  357.          lea.l    DeviceList(a6),a0                   ; get ptr to device list
  358.          jsr      _LVOFindName(a6)                    ; go find it
  359.          tst.l    d0                                  ; found?
  360.          beq.b    10$                                 ; nope, branch
  361.          ;
  362.          movea.l  d0,a1                               ; xfer device ptr
  363.          jsr      _LVORemDevice(a6)                   ; remove it
  364.          ;
  365.          ;        We then retry the allocate.
  366.          ;
  367. 10$      move.l   (sp),d0                             ; get unit
  368.          lea.l    Name(pc),a1                         ; get lock name
  369.          movea.l  vb_MiscBase(a5),a6                  ; get MiscBase
  370.          jsr      _LVOAllocMiscResource(a6)           ; go allocate it
  371.          ;
  372. 20$      addq.l   #4,sp                               ; restore stack ptr
  373.          movea.l  (sp)+,a6                            ; restore base ptr
  374.          rts                                          ; return
  375.          ;
  376.          ;
  377.          ;
  378. initResources:
  379.          move.l   a1,-(sp)                            ; save register
  380.          ;
  381.          lea.l    miscresource(pc),a1                 ; ptr to resource name
  382.          jsr      _LVOOpenResource(a6)                ; go open it
  383.          move.l   d0,vb_MiscBase(a5)                  ; save base
  384.          ;
  385.          moveq    #MR_SERIALPORT,d0                   ; set unit number
  386.          bsr.b    allocResource                       ; go allocate it
  387.          tst.l    d0                                  ; did we get it?
  388.          bne.b    20$                                 ; nope, error
  389.          ;
  390.          moveq    #MR_SERIALBITS,d0                   ; set unit number
  391.          bsr.b    allocResource                       ; go allocate it
  392.          tst.l    d0                                  ; did we get it?
  393.          bne.b    10$                                 ; nope, error
  394.          ;
  395.          bsr      getPrefs                            ; get default preferences
  396.          tst.l    d0                                  ; got 'em?
  397.          beq.b    30$                                 ; yep, branch
  398.          ;
  399.          moveq    #MR_SERIALPORT,d0                   ; set unit
  400.          movea.l  vb_MiscBase(a5),a6                  ; get MiscBase
  401.          jsr      _LVOFreeMiscResource(a6)            ; release the resource
  402.          ;
  403. 10$      moveq    #MR_SERIALPORT,d0                   ; set unit
  404.          movea.l  vb_MiscBase(a5),a6                  ; get MiscBase
  405.          jsr      _LVOFreeMiscResource(a6)            ; release the resource
  406.          movea.l  SysBase(pc),a6                      ; restore ExecBase
  407.          ;
  408. 20$      moveq    #SerErr_DevBusy,d0                  ; set error status
  409.          bra      40$                                 ; go return
  410.          ;
  411. 30$      moveq    #0,d1                               ; clear flags
  412.          moveq    #UNIT_VBLANK,d0                     ; set unit
  413.          lea.l    timerReq(pc),a1                     ; ptr to timer request
  414.          lea.l    timerdevice(pc),a0                  ; ptr to device name
  415.          jsr      _LVOOpenDevice(a6)                  ; go open it
  416.          ;
  417.          DISABLE                                      ; disable interrupts
  418.          ;
  419.          lea.l    _ciab,a1                            ; get ptr to ciab
  420.          move.b   ciaddra(a1),vb_SaveDDRA(a5)         ; save DDR value
  421.          andi.b   #PRTMASK,ciaddra(a1)                ; make serial bits input
  422.          move.b   ciapra(a1),vb_SavePRA(a5)           ; save PR value
  423.          ori.b    #CIAF_COMDTR|CIAF_COMRTS,ciaddra(a1) ; make DTR/RTS output
  424.          andi.b   #CIAF_COMCTS|CIAF_COMDSR|PRTMASK,ciapra(a1) ; make CTS/DSR input
  425.          andi.b   #CIAF_COMDTR|CIAF_COMRTS|PRTMASK,ciaddra(a1) ; turn on DTR/RTS
  426.          ;
  427.          moveq    #INTB_PORTS,d0                      ; get interrupt number
  428.          lea.l    VBInterrupt(pc),a1                  ; get interrupt ptr
  429.          jsr      _LVOAddIntServer(a6)                ; add it to the list
  430.          ;
  431.          bsr      getVBR                              ; get vector base (in A0)
  432.          ;
  433.          move.l   LVL1VEC(a0),vb_OldLevel1(a5)        ; save original vector
  434.          lea.l    level1(pc),a1                       ; get new vector ptr
  435.          move.l   a1,LVL1VEC(a0)                      ; set new vector
  436.          ;
  437.          move.l   LVL5VEC(a0),vb_OldLevel5(a5)        ; save original vector
  438.          lea.l    level5(pc),a1                       ; get new vector ptr
  439.          move.l   a1,LVL5VEC(a0)                      ; set new vector
  440.          ;
  441.          lea.l    _custom,a1                          ; get ptr to custom chips
  442.          move.w   #INTF_RBF|INTF_TBE,intreq(a1)       ; clear pending interrupts
  443.          move.w   #INTF_SETCLR|INTF_RBF|INTF_TBE,intena(a1) ; enable RBF & TBE
  444.          ;
  445.          addq.b   #1,vb_Initialized(a5)               ; set flag
  446.          moveq    #0,d0                               ; set good status
  447.          ;
  448.          ENABLE                                       ; enable interrupts
  449.          ;
  450. 40$      movea.l  (sp)+,a1                            ; restore register
  451.          rts                                          ; return
  452.          ;
  453.          ;        Get system preferences
  454.          ;
  455. getPrefs:
  456.          move.l   a1,-(sp)                            ; save registers
  457.          ;
  458.          lea.l    intuitlib(pc),a1                    ; ptr to library name
  459.          jsr      _LVOOldOpenLibrary(a6)              ; go open it (any version)
  460.          movea.l  d0,a6                               ; get intuition base
  461.          ;
  462.          move.l   #(pf_SerParShk+3)&$fffffffc,d0      ; size we need (aligned)
  463.          suba.l   d0,sp                               ; reserve space
  464.          ;
  465.          movea.l  sp,a0                               ; set data area ptr
  466.          jsr      _LVOGetPrefs(a6)                    ; get preferences
  467.          ;
  468.          movea.l  a6,a1                               ; get intuition base
  469.          movea.l  SysBase(pc),a6                      ; restore ExecBase
  470.          jsr      _LVOCloseLibrary(a6)                ; close it
  471.          ;
  472.          moveq    #$0f,d1                             ; set mask
  473.          and.b    pf_SerStopBuf(sp),d1                ; get bufsize index
  474.          addq.l   #8,d1                               ; calc shift value
  475.          moveq    #2,d0                               ; get 1<<1
  476.          lsl.l    d1,d0                               ; get default bufsize
  477.          move.l   d0,vb_DefRBufLen(a5)                ; and store
  478.          ;
  479.          moveq    #0,d1                               ; clear upper half
  480.          move.w   pf_BaudRate(sp),d1                  ; get baud rate
  481.          add.l    d1,d1                               ; generate offset
  482.          move.w   baudTable(pc,d1.w),d1               ; get default baud
  483.          move.l   d1,vb_DefBaud(a5)                   ; and store
  484.          ;
  485.          bsr      internalReset                       ; go init baud and buffer
  486.          ;
  487.          lea.l    (pf_SerParShk+3)&$fffffffc(sp),sp   ; restore stack
  488.          movea.l  (sp)+,a1                            ; restore registers
  489.          rts                                          ; return ( status in D0 )
  490.          ;
  491.          ;        Preferences baud lookup table
  492.          ;
  493. baudTable:
  494.          dc.w     112,300,1200,2400,4800,9600,19200,31250
  495.          ;
  496.          ;        Set exception vectors
  497.          ;
  498. getVBR:
  499.          move.l   a5,-(sp)                            ; save registers
  500.          suba.l   a0,a0                               ; ptr to vector base (68000)
  501.          btst.b   #AFB_68010,AttnFlags+1(a6)          ; 68010 or higher?
  502.          beq.b    10$                                 ; nope, go set vector
  503.          lea.l    20$(pc),a5                          ; ptr to routine
  504.          jsr      _LVOSupervisor(a6)                  ; get into supervisor state
  505. 10$      movea.l  (sp)+,a5                            ; restore register
  506.          rts                                          ; return
  507. 20$      movec.l  vbr,a0                              ; get vector base
  508.          rte                                          ; return
  509.          ;
  510.          ;
  511.          ;
  512. freeResources:
  513.          move.l   a1,-(sp)                            ; save registers
  514.          ;
  515.          DISABLE                                      ; disable interrupts
  516.          ;
  517.          bsr      getVBR                              ; get vector base (in A0)
  518.          ;
  519.          moveq    #1,d0                               ; set not restored code
  520.          ;
  521.          lea.l    level1(pc),a1                       ; get our vector ptr
  522.          cmpa.l   LVL1VEC(a0),a1                      ; do they match?
  523.          bne      10$                                 ; nope, can't restore
  524.          ;
  525.          lea.l    level5(pc),a1                       ; get our vector ptr
  526.          cmpa.l   LVL5VEC(a0),a1                      ; do they match?
  527.          bne      10$                                 ; nope, can't restore
  528.          ;
  529.          move.l   vb_OldLevel1(a5),LVL1VEC(a0)        ; restore original vector
  530.          move.l   vb_OldLevel5(a5),LVL5VEC(a0)        ; restore original vector
  531.          ;
  532.          moveq    #INTB_PORTS,d0                      ; get interrupt number
  533.          lea.l    VBInterrupt(pc),a1                  ; get interrupt ptr
  534.          jsr      _LVORemIntServer(a6)                ; remove it from the list
  535.          ;
  536.          move.w   #INTF_RBF|INTF_TBE,d0               ; indicate serial interrupts
  537.          move.w   d0,_intena                          ; disable interrupts
  538.          move.w   d0,_intreq                          ; clear pending interrupts
  539.          ;
  540.          bsr      freeBuf                             ; free allocated buffers
  541.          ;
  542.          lea.l    _ciab,a0                            ; get pointer to ciab
  543.          move.b   ciaddra(a0),d0                      ; get DDR value
  544.          andi.b   #PRTMASK,d0                         ; save printer bits
  545.          ori.b    #~PRTMASK,d0                        ; set serial bits to output
  546.          move.b   d0,ciaddra(a0)                      ; store value
  547.          ;
  548.          move.b   ciapra(a0),d0                       ; get PR value
  549.          andi.b   #PRTMASK,d0                         ; mask out serial bits
  550.          move.b   vb_SavePRA(a5),d1                   ; get saved value
  551.          andi.b   #~PRTMASK,d1                        ; mask out printer bits
  552.          or.b     d1,d0                               ; combine the two
  553.          move.b   d0,ciapra(a0)                       ; and store
  554.          ;
  555.          move.b   ciaddra(a0),d0                      ; get DDR value
  556.          andi.b   #PRTMASK,d0                         ; mask out serial bits
  557.          move.b   vb_SaveDDRA(a5),d1                  ; get saved value
  558.          andi.b   #~PRTMASK,d1                        ; mask out printer bits
  559.          or.b     d1,d0                               ; combine the two
  560.          move.b   d0,ciaddra(a0)                      ; and store
  561.          ;
  562.          lea.l    timerReq(pc),a1                     ; get ptr to timer request
  563.          jsr      _LVOCloseDevice(a6)                 ; go close it
  564.          ;
  565.          movea.l  vb_MiscBase(a5),a6                  ; get MiscBase
  566.          moveq    #MR_SERIALBITS,d0                   ; set unit
  567.          jsr      _LVOFreeMiscResource(a6)            ; release the resource
  568.          ;
  569.          moveq    #MR_SERIALPORT,d0                   ; set unit
  570.          jsr      _LVOFreeMiscResource(a6)            ; release the resource
  571.          movea.l  SysBase(pc),a6                      ; restore ExecBase
  572.          ;
  573.          ENABLE                                       ; enable interrupts
  574.          ;
  575.          subq.b   #1,vb_Initialized(a5)               ; clear flag
  576.          moveq    #0,d0                               ; free up everything
  577.          ;
  578. 10$      movea.l  (sp)+,a1                            ; restore registers
  579.          rts                                          ; return
  580.          ;
  581.          ;        Device Close routine
  582.          ;
  583. dev_Close:
  584.          ;
  585.          moveq    #-1,d0                              ; invalidate
  586.          move.l   d0,IO_DEVICE(a1)                    ;   device
  587.          ;
  588.          subq.w   #1,LIB_OPENCNT(a6)                  ; decr open count
  589.          bne.b    dev_Null                            ; still open? yep, branch
  590.          ;
  591.          move.l   a5,-(sp)                            ; save registers
  592.          movea.l  a6,a5                               ; save base
  593.          movea.l  SysBase(pc),a6                      ; get ExecBase
  594.          ;
  595.          bsr      freeResources                       ; free allocated resources
  596.          ;
  597.          movea.l  a5,a6                               ; restore base
  598.          movea.l  (sp)+,a5                            ; restore registers
  599.          ;
  600.          tst.l    d0                                  ; freed?
  601.          bne.b    dev_Null                            ; nope, can't expunge, exit
  602.          ;
  603.          clr.b    vb_SerFlags(a6)                     ; clear flags
  604.          ;
  605.          btst.b   #LIBB_DELEXP,LIB_FLAGS(a6)          ; delayed expunge set?
  606.          beq.b    dev_Null                            ; nope, go exit
  607.          ;
  608.          ;        Device Expunge routine (also fall through from dev_Close)
  609.          ;
  610. dev_Expunge:
  611.          bset.b   #LIBB_DELEXP,LIB_FLAGS(a6)          ; Set expunge flag
  612.          tst.w    LIB_OPENCNT(a6)                     ; currently open?
  613.          bne.b    dev_Null                            ; yep, so just exit
  614.          ;
  615.          move.l   vb_SegList(a6),d0                   ; get seglist ptr
  616.          movem.l  d0/a5/a6,-(sp)                      ; save registers (save D0!)
  617.          ;
  618.          movea.l  a6,a5                               ; save base
  619.          movea.l  SysBase(pc),a6                      ; get ExecBase
  620.          movea.l  a5,a1                               ; get base
  621.          jsr      _LVORemove(a6)                      ; Remove it
  622.          ;
  623.          movea.l  a5,a1                               ; get base
  624.          moveq    #0,d0                               ; clear work
  625.          move.w   LIB_NEGSIZE(a5),d0                  ; calculate
  626.          suba.w   d0,a1                               ;   memory address
  627.          add.w    LIB_POSSIZE(a5),d0                  ;     and size
  628.          jsr      _LVOFreeMem(a6)                     ; free it
  629.          ;
  630.          movem.l  (sp)+,d0/a5/a6                      ; restore registers
  631.          rts                                          ; return (seglist in D0!)
  632.          ;
  633.          ;        Device "ExtFunc" routine
  634.          ;
  635. dev_Null:
  636.          moveq    #0,d0                               ; set return code
  637.          rts                                          ; return
  638.          ;
  639.          ;
  640.          ;
  641.          IFEQ     DEBUG-1
  642. printIO:
  643.          movem.l  d0-d7/a0-a6,-(sp)
  644.          addq.l   #1,ioctr
  645.          move.l   ioctr,-(sp)
  646.          move.l   a1,-(sp)
  647.          move.l   a0,-(sp)
  648.          pea.l    0$
  649.          pea.l    Name
  650.          DISABLE  TBE|INTF_PORTS
  651.          jsr      _SendText(pc)
  652.          ENABLE   TBE|INTF_PORTS
  653.          lea.l    20(sp),sp
  654.  
  655.          moveq    #0,d0
  656.          move.w   IO_COMMAND(a1),d0
  657.          move.l   d0,-(sp)
  658.          move.l   MN_REPLYPORT(a1),-(sp)
  659.          moveq    #0,d0
  660.          move.b   LN_TYPE(a1),d0
  661.          move.l   d0,-(sp)
  662.          pea.l    1$
  663.          pea.l    Name
  664.          DISABLE  TBE|INTF_PORTS
  665.          jsr      _SendText(pc)
  666.          ENABLE   TBE|INTF_PORTS
  667.          lea.l    20(sp),sp
  668.  
  669.          move.l   IO_LENGTH(a1),-(sp)
  670.          moveq    #0,d0
  671.          move.b   IO_ERROR(a1),d0
  672.          move.l   d0,-(sp)
  673.          move.b   IO_FLAGS(a1),d0
  674.          move.l   d0,-(sp)
  675.          pea.l    2$
  676.          pea.l    Name
  677.          DISABLE  TBE|INTF_PORTS
  678.          jsr      _SendText(pc)
  679.          ENABLE   TBE|INTF_PORTS
  680.          lea.l    20(sp),sp
  681.  
  682.          move.l   IO_EXTFLAGS(a1),-(sp)
  683.          move.l   IO_RBUFLEN(a1),-(sp)
  684.          move.l   IO_ACTUAL(a1),-(sp)
  685.          pea.l    3$
  686.          pea.l    Name
  687.          DISABLE  TBE|INTF_PORTS
  688.          jsr      _SendText(pc)
  689.          ENABLE   TBE|INTF_PORTS
  690.          lea.l    20(sp),sp
  691.  
  692.          moveq    #0,d0
  693.          move.b   IO_WRITELEN(a1),d0
  694.          move.l   d0,-(sp)
  695.          move.b   IO_READLEN(a1),d0
  696.          move.l   d0,-(sp)
  697.          move.l   IO_BAUD(a1),-(sp)
  698.          pea.l    4$
  699.          pea.l    Name
  700.          DISABLE  TBE|INTF_PORTS
  701.          jsr      _SendText(pc)
  702.          ENABLE   TBE|INTF_PORTS
  703.          lea.l    20(sp),sp
  704.  
  705.          moveq    #0,d0
  706.          move.w   IO_STATUS(a1),d0
  707.          move.l   d0,-(sp)
  708.          moveq    #0,d0
  709.          move.b   IO_SERFLAGS(a1),d0
  710.          move.l   d0,-(sp)
  711.          move.b   IO_STOPBITS(a1),d0
  712.          move.l   d0,-(sp)
  713.          pea.l    5$
  714.          pea.l    Name
  715.          DISABLE  TBE|INTF_PORTS
  716.          jsr      _SendText(pc)
  717.          ENABLE   TBE|INTF_PORTS
  718.          lea.l    20(sp),sp
  719.          movem.l  (sp)+,d0-d7/a0-a6
  720.          rts
  721. 0$       dc.b     '%ls - I/O     %8lx, Cnt = %ld',0
  722. 1$       DC.B     'Type    %8ld     ReplyPort %8lx    Command  %8ld',0
  723. 2$       DC.B     'Flags   %8lx     Error     %8ld    Length   %8ld',0
  724. 3$       DC.B     'Actual  %8ld     RBufLen   %8ld    ExtFlags %8lx',0
  725. 4$       DC.B     'Baud    %8ld     ReadLen   %8ld    WriteLen %8ld',0
  726. 5$       DC.B     'StopBit %8ld     SerFlags  %8lx    Status   %8lx',0
  727.          ;
  728.          ;
  729.          ;
  730. abortIOs dc.b     'Abort Start',0
  731. abortIOe dc.b     'Abort End',0
  732. abortIOa dc.b     'Aborting',0
  733. beginIOs dc.b     'Begin Start',0
  734. beginIOe dc.b     'Begin End',0
  735. openIO   dc.b     'Open IO',0
  736. replyIO  dc.b     'replyIO',0
  737.          ds.l     0
  738. ioctr    dc.l     0
  739.          ENDC
  740.          ;
  741. cmdTable dc.w     cmd_Invalid-cmdTable                ; CMD_INVALID
  742.          dc.w     cmd_Reset-cmdTable                  ; CMD_RESET
  743.          dc.w     cmd_Read-cmdTable                   ; CMD_READ
  744.          dc.w     cmd_Write-cmdTable                  ; CMD_WRITE
  745.          dc.w     cmd_Invalid-cmdTable                ; CMD_UPDATE
  746.          dc.w     cmd_Clear-cmdTable                  ; CMD_CLEAR
  747.          dc.w     cmd_Invalid-cmdTable                ; CMD_STOP
  748.          dc.w     cmd_Invalid-cmdTable                ; CMD_START
  749.          dc.w     cmd_Flush-cmdTable                  ; CMD_FLUSH
  750.          dc.w     sdcmd_Query-cmdTable                ; SDCMD_QUERY
  751.          dc.w     sdcmd_Break-cmdTable                ; SDCMD_BREAK
  752. endTable dc.w     sdcmd_SetParams-cmdTable            ; SDCMD_SETPARAMS
  753.          ;
  754.          ;        Device BeginIO routine
  755.          ;
  756. dev_BeginIO:
  757.          move.l   a5,-(sp)                            ; save register
  758.          movea.l  a6,a5                               ; save base
  759.          movea.l  SysBase(pc),a6                      ; get ExecBase
  760.          DEBUGIO  beginIOs
  761.          ;
  762.          move.b   #NT_MESSAGE,LN_TYPE(a1)             ; set type
  763.          clr.b    IO_ERROR(a1)                        ; clear error
  764.          ;
  765.          andi.b   #~(IOSERF_QUEUED|IOSERF_ACTIVE),IO_FLAGS(a1) ; clear flags
  766.          ;
  767.          move.w   IO_COMMAND(a1),d0                   ; get command
  768.          add.w    d0,d0                               ; multiply by 2
  769.          cmpi.w   #endTable-cmdTable,d0               ; in range?
  770.          bhi.b    30$                                 ; nope, error
  771.          ;
  772.          move.w   cmdTable(pc,d0.w),d0                ; get routine offset
  773.          jsr      cmdTable(pc,d0.w)                   ; go do it
  774.          tst.l    d0                                  ; I/O completed?
  775.          bne.b    19$                                 ; nope, go return
  776.          ;
  777. 10$      DEBUGIO  beginIOe
  778.          btst.b   #IOB_QUICK,IO_FLAGS(a1)             ; need to reply?
  779.          bne.b    20$                                 ; nope, branch
  780. 15$      jsr      _LVOReplyMsg(a6)                    ; send it back
  781.          ;
  782. 19$      bclr.b   #IOB_QUICK,IO_FLAGS(a1)             ; clear quick bit
  783. 20$      movea.l  a5,a6                               ; restore base
  784.          movea.l  (sp)+,a5                            ; restore register
  785.          rts                                          ; return
  786.          ;
  787. 30$      move.b   #IOERR_NOCMD,IO_ERROR(a1)           ; invalid command
  788.          bra.b    10$                                 ; branch
  789.          ;
  790.          ;        Device AbortIO routine
  791.          ;
  792. dev_AbortIO:
  793.          move.l   a5,-(sp)                            ; save registers
  794.          movea.l  a6,a5                               ; save base
  795.          movea.l  SysBase(pc),a6                      ; get ExecBase
  796.          DEBUGIO  abortIOs
  797.          ;
  798.          DISABLE                                      ; disable interrupts
  799.          ;
  800.          btst.b   #IOSERB_QUEUED,IO_FLAGS(a1)         ; queued request?
  801.          bne.b    40$                                 ; yep, branch
  802.          ;
  803.          btst.b   #IOSERB_ACTIVE,IO_FLAGS(a1)         ; active request?
  804.          beq.b    10$                                 ; nope, just exit
  805.          ;
  806.          move.w   IO_COMMAND(a1),d0                   ; get command
  807.          subq.w   #CMD_READ,d0                        ; was it a read?
  808.          beq.b    20$                                 ; yep, go process
  809.          ;
  810.          subq.w   #CMD_WRITE-CMD_READ,d0              ; was it a write?
  811.          beq.b    30$                                 ; yep, go process
  812.          ;
  813.          subq.w   #SDCMD_BREAK-CMD_WRITE,d0           ; was it a break?
  814.          beq.b    30$                                 ; yep, go process
  815.          ;
  816.          ;        Fall through or enter from below
  817.          ;
  818. 10$      ENABLE                                       ; enable ints and return
  819. 15$      movea.l  a5,a6                               ; restore base
  820.          movea.l  (sp)+,a5                            ; restore registers
  821.          rts                                          ; return
  822.          ;
  823.          ;        Abort an active read request
  824.          ;
  825. 20$      clr.l    cr_IOReq                            ; no longer active
  826.          bra.b    50$                                 ; go set flags
  827.          ;
  828.          ;        Abort an active write request
  829.          ;
  830. 30$      clr.l    cw_Length                           ; no longer active
  831.          clr.l    cw_IOReq                            ; no longer active
  832.          move.l   cw_Buffer(pc),d0                    ; get buffer ptr
  833.          sub.l    IO_DATA(a1),d0                      ; calc number of bytes xfer'd
  834.          move.l   d0,IO_ACTUAL(a1)                    ; store
  835.          ;
  836.          ;        Force a TBE interrupt to get the next write going.
  837.          ;
  838.          move.w   #INTF_SETCLR|INTF_TBE,_intreq       ; make TBE pending
  839.          bra.b    50$                                 ; go set flags
  840.          ;
  841.          ;        Remove I/O from queue.
  842.          ;
  843. 40$      move.l   a1,-(sp)                            ; save ptr
  844.          jsr      _LVORemove(a6)                      ; remove it
  845.          movea.l  (sp)+,a1                            ; restore ptr
  846.          ;
  847.          ;        Set error and return I/O
  848.          ;
  849. 50$      move.b   #IOERR_ABORTED,IO_ERROR(a1)         ; set error code
  850.          move.b   IO_FLAGS(a1),d1                     ; get flags
  851.          bset.b   #IOSERB_ABORT,d1                    ; set abort flag
  852.          andi.b   #~(IOSERF_QUEUED|IOSERF_ACTIVE),d1  ; clear flags
  853.          move.b   d1,IO_FLAGS(a1)                     ; store flags
  854.          DEBUGIO  abortIOe
  855.          btst.b   #IOB_QUICK,d1                       ; need to reply?
  856.          bne.b    10$                                 ; nope, branch
  857.          jsr      _LVOReplyMsg(a6)                    ; send it back
  858.          bra.b    10$                                 ; branch to return
  859.          ;
  860.          ;        Abort all active/queued commands and reset internal state
  861.          ;
  862. cmd_Reset:
  863.          move.l   a1,-(sp)                            ; save I/O request
  864.          bsr.b    cmd_Flush                           ; go abort queued requests
  865.          ;
  866.          DISABLE                                      ; disable interrupts
  867.          ;
  868.          ;        This must follow the DISABLE
  869.          ;
  870.          exg      a5,a6                               ; exchange base and ExecBase
  871.          ;
  872.          move.l   cr_IOReq(pc),d0                     ; active read?
  873.          beq.b    10$                                 ; nope, branch
  874.          movea.l  d0,a1                               ; get I/O request
  875.          bsr      dev_AbortIO                         ; go abort it
  876.          ;
  877.          ;
  878.          ;
  879. 10$      move.l   cw_IOReq(pc),d0                     ; active write?
  880.          beq.b    20$                                 ; nope, branch
  881.          movea.l  d0,a1                               ; get I/O request
  882.          bsr      dev_AbortIO                         ; go abort it
  883.          ;
  884. 20$      exg      a5,a6                               ; restore base and ExecBase
  885.          movea.l  (sp)+,a1                            ; restore I/O request
  886.          moveq    #8,d0                               ; get char size
  887.          move.b   d0,IO_READLEN(a1)                   ; set read length
  888.          move.b   d0,IO_WRITELEN(a1)                  ; set write length
  889.          moveq    #1,d0                               ; get stop bits
  890.          move.b   d0,IO_STOPBITS(a1)                  ; set stop bits
  891.          move.l   vb_DefBaud(a5),IO_BAUD(a1)          ; set to default baud
  892.          move.l   vb_DefRBufLen(a5),IO_RBUFLEN(a1)    ; set to default buflen
  893.          bsr      internalReset                       ; go set/verify parameters
  894.          move.b   d0,IO_ERROR(a1)                     ; set error code
  895.          ENABLE                                       ; enable interrupts
  896.          ;
  897.          ;        Set RC and return
  898.          ;
  899.          moveq    #0,d0                               ; I/O complete
  900.          rts                                          ; return
  901.          ;
  902.          ;        Abort all "queued" requests, leaving all active alone.
  903.          ;
  904. cmd_Flush:
  905.          movem.l  a1/a2,-(sp)                         ; save registers
  906.          DISABLE                                      ; disable interrupts
  907.          ;
  908.          ;        Abort all queued read requests.
  909.          ;
  910.          lea.l    readQ(pc),a2                        ; get ptr to read queue
  911.          bsr.b    20$                                 ; branch to abort
  912.          ;
  913.          ;        Abort all queued write requests.
  914.          ;
  915.          lea.l    writeQ(pc),a2                       ; get ptr to write queue
  916.          bsr.b    20$                                 ; branch to abort
  917.          ;
  918.          ;        Enable, restore, and return to caller
  919.          ;
  920.          ENABLE                                       ; enable interrupts
  921.          movem.l  (sp)+,a1/a2                         ; restore registers
  922.          ;
  923.          ;        Set RC and return
  924.          ;
  925.          moveq    #0,d0                               ; I/O complete
  926.          ;
  927.          ;        !!!NOTE!!!  In a mad attempt to save 2 bytes, this RTS is used
  928.          ;        by the subroutine below.  Why waste 'em?  B-)
  929.          ;
  930. 10$      rts                                          ; return ( used below too!! )
  931.          ;
  932.          ;        Subroutine to remove and reply each I/O request.
  933.          ;
  934. 20$      movea.l  a2,a0                               ; get list ptr
  935.          jsr      _LVORemHead(a6)                     ; get I/O request
  936.          tst.l    d0                                  ; end of list?
  937.          beq.b    10$                                 ; yep, branch to return
  938.          ;
  939.          movea.l  d0,a1                               ; get I/O request
  940.          bclr.b   #IOSERB_QUEUED,IO_FLAGS(a1)         ; no longer queued
  941.          moveq    #IOERR_ABORTED,d0                   ; indicate aborted
  942.          move.b   d0,IO_ERROR(a1)                     ; store status
  943.          ;
  944.          jsr      _LVOReplyMsg(a6)                    ; send it back
  945.          bra.b    20$                                 ; continue with next
  946.          ;
  947.          ;        Process a CMD_READ request.
  948.          ;
  949. cmd_Read:
  950.          ;
  951.          ;        Zero length requests just get returned.
  952.          ;
  953.          clr.l    IO_ACTUAL(a1)                       ; clear bytes read
  954.          move.l   IO_LENGTH(a1),d0                    ; get length and test
  955.          beq.b    20$                                 ; yep, leave
  956.          ;
  957.          ;        This can be used to circumvent a bug in NComm 3.0 which
  958.          ;        references the buffer even when there was nothing read.
  959.          ;
  960.          IFD      NCOMM
  961.          move.l   IO_DATA(A1),a0                      ; get data pointer
  962.          clr.b    (a0)                                ; clear first byte in buffer
  963.          ENDC
  964.          ;
  965.          ;        The disable counter works just like exec's TDNestCnt field.  It's
  966.          ;        initialized to -1.  After incrementing, if it is 0, then we
  967.          ;        can attempt to process this request immediately.  If it's > 0,
  968.          ;        then we're already disabled and we must queue this request.
  969.          ;
  970.          addq.b   #1,disableRead                      ; incr disable count
  971.          bgt.b    50$                                 ; >0, already disabled
  972.          ;
  973.          ;        If we're already processing an request, this one has to wait
  974.          ;        until that one is done, so go queue it.
  975.          ;
  976.          move.l   cr_IOReq(pc),d1                     ; have an active request?
  977.          bne.b    50$                                 ; yep, go queue this one
  978.          ;
  979.          ;        If we don't have enough bytes to satisfy this request then go
  980.          ;        queue it.
  981.          ;
  982.          cmp.l    i_InCnt(pc),d0                      ; length > current bytes?
  983.          bgt.b    50$                                 ; yep, go queue it
  984.          ;
  985.          ;        Setup fields and go copy the data
  986.          ;
  987.          move.l   IO_DATA(a1),cr_OutPtr               ; get/set output ptr
  988.          move.l   IO_LENGTH(a1),cr_Length             ; get/set output count
  989.          bsr      copyData                            ; go copy 'em
  990.          moveq    #0,d0                               ; I/O complete
  991.          ;
  992.          ;        We're done, so back off the disable counter.
  993.          ;
  994. 10$      subq.b   #1,disableRead                      ; decr disable count
  995.          ;
  996.          ;        Return to caller
  997.          ;
  998. 20$      rts                                          ; return
  999.          ;
  1000.          ;        Just set flags and queue.  The read interrupt will handle it.
  1001.          ;
  1002. 50$      bset.b   #IOSERB_QUEUED,IO_FLAGS(a1)         ; indicate queued
  1003.          ;
  1004.          ;        Add this request to the end.
  1005.          ;
  1006.          DISABLE                                      ; disable interrupts
  1007.          lea.l    readQ(pc),a0                        ; get pointer to read queue
  1008.          move.l   a1,-(sp)                            ; save I/O request
  1009.          jsr      _LVOAddTail(a6)                     ; and queue it
  1010.          movea.l  (sp)+,a1                            ; restore I/O request
  1011.          ENABLE                                       ; enable interrupts
  1012.          ;
  1013.          ;        Indicate that this request was not handled immediatly.
  1014.          ;
  1015.          moveq    #1,d0                               ; I/O not complete
  1016.          bra.b    10$                                 ; branch to return
  1017.          ;
  1018.          ;        Process a CMD_WRITE request.
  1019.          ;
  1020. cmd_Write:
  1021.          clr.l    IO_ACTUAL(a1)                       ; clear bytes written
  1022.          move.l   IO_LENGTH(a1),d0                    ; get length and test
  1023.          beq.b    wbexit                              ; yep, leave
  1024.          ;
  1025.          ;        Entry point for Break command and fall through from cmd_Write.
  1026.          ;
  1027. sdcmd_Break:
  1028.          ;
  1029.          ;        Just set flags and queue. The TBE interrupt will handle it.
  1030.          ;
  1031.          bset.b   #IOSERB_QUEUED,IO_FLAGS(a1)         ; indicate queued
  1032.          ;
  1033.          ;        Protect.
  1034.          ;
  1035.          DISABLE                                      ; disable interrupts
  1036.          ;
  1037.          ;        Add request to end of queue.
  1038.          ;
  1039.          lea.l    writeQ(pc),a0                       ; get queue list ptr
  1040.          move.l   a1,-(sp)                            ; save I/O request
  1041.          jsr      _LVOAddTail(a6)                     ; and queue it
  1042.          movea.l  (sp)+,a1                            ; restore I/O request
  1043.          ;
  1044.          ;        If we have an active request, don't force interrupt.
  1045.          ;
  1046.          move.l   cw_IOReq(pc),d0                     ; have an active request?
  1047.          bne.b    10$                                 ; yep, branch
  1048.          ;
  1049.          ;        Force a TBE interrupt to get the writes going.
  1050.          ;
  1051.          move.w   #INTF_SETCLR|INTF_TBE,_intreq       ; make TBE pending
  1052.          ;
  1053.          ;        Enable, set RC and return to caller.
  1054.          ;
  1055. 10$      ENABLE                                       ; enable interrupts
  1056.          moveq    #1,d0                               ; I/O not complete
  1057. wbexit   rts                                          ; return
  1058.          ;
  1059.          ;        Resets serial read buffer
  1060.          ;
  1061.          ;        Since this routine is called internally, it must NOT reference
  1062.          ;        the I/O request.
  1063.          ;
  1064. cmd_Clear:
  1065.          DISABLE                                      ; disable interrupts
  1066.          ;
  1067.          ;        Load registers
  1068.          ;
  1069.          move.l   vb_CurRBuf(a5),d0                   ; get internal buffer ptr
  1070.          move.l   vb_CurRBufLen(a5),d1                ; and internal buffer len
  1071.          lea.l    i_BufPtr(pc),a0                     ; get ptr internal control
  1072.          ;
  1073.          ;        Initialize global buffer variables
  1074.          ;
  1075.          move.l   d0,(a0)+                            ; store buffer ptr
  1076.          move.l   d0,(a0)+                            ; set current input ptr
  1077.          move.l   d0,(a0)+                            ; set current output ptr
  1078.          add.l    d1,d0                               ; add buffer length
  1079.          move.l   d0,(a0)+                            ; store ptr to end of buffer
  1080.          clr.l    (a0)+                               ; clear byte cnt
  1081.          move.l   vb_CurBaud(a5),d0                   ; get internal baud
  1082.          lsr.l    #4,d0                               ; divide by 16
  1083.          sub.l    d0,d1                               ; subtract from length
  1084.          move.l   d1,(a0)                             ; set threshold
  1085.          ;
  1086.          ;        Enable, set RC and return.
  1087.          ;
  1088.          ENABLE                                       ; enable interrupts
  1089.          moveq    #0,d0                               ; I/O complete
  1090.          rts                                          ; return
  1091.          ;
  1092.          ;
  1093.          ;
  1094. cmd_Invalid
  1095.          move.b   #IOERR_NOCMD,IO_ERROR(a1)           ; set bad status
  1096.          moveq    #0,d0                               ; I/O complete
  1097.          rts                                          ; return
  1098.          ;
  1099.          ;        Returns number of bytes currently in internal buffer and
  1100.          ;        current serial port status.
  1101.          ;
  1102.          ;        NOTE:  Not completely compatible with standard serial.device
  1103.          ;        since it doesn't return the upper byte of IO_STATUS.
  1104.          ;
  1105. sdcmd_Query:
  1106.          DISABLE                                      ; disable interrupts
  1107.          moveq    #0,d0                               ; clear d0
  1108.          move.b   _ciabpra,d0                         ; get PR register
  1109.          andi.w   #~PRTMASK,d0                        ; zap printer bits
  1110.          ;
  1111.          ;        Uncomment the following to turn on the DSR bit.  This was done
  1112.          ;        for a user whose DSR pin did not function.
  1113.          ;
  1114. ;         bclr     #CIAB_COMDSR,d0                     ; set DSR
  1115.          ;
  1116.          ;
  1117.          ;
  1118.          move.w   d0,IO_STATUS(a1)                    ; store status
  1119.          move.l   i_InCnt(pc),IO_ACTUAL(a1)           ; byte left in buffer
  1120.          ;
  1121.          ;        Enable, set RC and return.
  1122.          ;
  1123.          ENABLE                                       ; enable interrupts
  1124.          moveq    #0,d0                               ; I/O complete
  1125.          rts                                          ; return
  1126.          ;
  1127.          ;
  1128.          ;
  1129. sdcmd_SetParams:
  1130.          ;
  1131.          ;        Validate the read, write, and stop bit lengths.
  1132.          ;
  1133.          moveq    #8,d0                               ; get char length
  1134.          cmp.b    IO_READLEN(a1),d0                   ; 8 bit chars for read?
  1135.          bne.b    40$                                 ; nope, branch
  1136.          cmp.b    IO_WRITELEN(a1),d0                  ; 8 bit chars for write?
  1137.          bne.b    40$                                 ; nope, branch
  1138.          moveq    #1,d0                               ; get stop bits
  1139.          cmp.b    IO_STOPBITS(a1),d0                  ; 1 stop bit?
  1140.          bne.b    40$                                 ; nope, branch
  1141.          ;
  1142.          ;        Get and validate the baud rate.
  1143.          ;
  1144.          move.l   IO_BAUD(a1),d1                      ; get baud from I/O req
  1145.          bne.b    20$                                 ; specified?
  1146.          move.l   vb_CurBaud(a5),d1                   ; get current baud from base
  1147.          bne.b    20$                                 ; specified?
  1148.          move.l   vb_DefBaud(a5),d1                   ; get default baud from base
  1149. 20$      cmpi.l   #110,d1                             ; too low?
  1150.          blt.b    40$                                 ; error
  1151.          cmpi.l   #292000,d1                          ; too high?
  1152.          bgt.b    40$                                 ; error
  1153.          ;
  1154.          ;        Get and validate the buffer length.
  1155.          ;
  1156.          move.l   IO_RBUFLEN(a1),d0                   ; get buffer length
  1157.          bne.b    30$                                 ; specified?
  1158.          move.l   vb_CurRBufLen(a5),d0                ; get current from base
  1159.          bne.b    30$                                 ; specified?
  1160.          move.l   vb_DefRBufLen(a5),d0                ; get default from base
  1161.          ;
  1162. 30$      bsr.b    internalReset                       ; go init baud and buffer
  1163. 35$      move.b   d0,IO_ERROR(a1)                     ; set error code
  1164.          bne.b    39$
  1165.          ;
  1166.          ;        If the 7wire bit is not on, we will only use 3-wire protocol
  1167.          ;
  1168.          moveq    #0,d0                               ; clear flag
  1169.          btst.b   #SERB_7WIRE,IO_SERFLAGS(a1)         ; use 7wire handshaking?
  1170.          beq.b    36$                                 ; nope, branch
  1171.          moveq    #1,d0                               ; set flag
  1172. 36$      move.b   d0,Handshake                        ; store flag
  1173.          ;
  1174.          ;        Set RC and return.
  1175.          ;
  1176. 39$      moveq    #0,d0                               ; I/O complete
  1177.          rts                                          ; return
  1178.          ;
  1179.          ;        Invalid parm detected.
  1180.          ;
  1181. 40$      moveq    #SerErr_InvParam,d0                 ; set error
  1182.          bra.b    35$                                 ; go return
  1183.          ;
  1184.          ;        Reset the buffer and baud rate
  1185.          ;
  1186.          ;        Registers:  D0 = Buffer length
  1187.          ;                    D1 = Baud rate
  1188.          ;
  1189. internalReset:
  1190.          ;
  1191.          ;        Disable interrupts.
  1192.          ;
  1193.          DISABLE                                      ; disable interrupts
  1194.          ;
  1195.          ;        Save buffer length and go set serper.
  1196.          ;
  1197.          move.l   d0,-(sp)                            ; save D0
  1198.          move.l   d1,d0                               ; get baud rate
  1199.          bsr.b    setPeriod                           ; go set the serper register
  1200.          move.l   (sp)+,d0                            ; restore D0
  1201.          ;
  1202.          ;        Determine if the buffer length is adequate for the selected CPS.
  1203.          ;        If not, use 64K for the length.
  1204.          ;
  1205.          move.l   vb_CurBaud(a5),d1                   ; get current baud
  1206.          lsr.l    #$3,d1                              ; divide by 8
  1207.          cmp.l    d1,d0                               ; buflen > CPS
  1208.          bhi.b    10$                                 ; yep, branch
  1209.          move.l   #65536,d0                           ; else use 64K
  1210.          ;
  1211. 10$      bsr.b    allocBuf                            ; go allocate a new buffer
  1212.          ;
  1213.          ;        Enable and return to caller.
  1214.          ;
  1215.          ENABLE                                       ; enable interrupts
  1216.          rts                                          ; return (D0 has status)
  1217.          ;
  1218.          ;        Set serial period register
  1219.          ;
  1220. setPeriod:
  1221.          cmp.l    vb_CurBaud(a5),d0                   ; current baud = new baud?
  1222.          beq.b    40$                                 ; yep, just exit
  1223.          move.l   d0,vb_CurBaud(a5)                   ; save new baud
  1224.          move.l   d0,d1                               ; save again
  1225.          lsl.l    #3,d0                               ; baud *= 8
  1226.          sub.l    d1,d0                               ; baud -= saved baud
  1227.          move.l   #25000000,d1                        ; get NTSC base
  1228.          cmpi.b   #50,PowerSupplyFrequency(a6)        ; PAL machine?
  1229.          bne.b    10$                                 ; nope, branch
  1230.          move.l   #24772416,d1                        ; get PAL base
  1231. 10$      cmpi.l   #$FFFF,d0                           ; Divide
  1232.          ble.b    20$                                 ;
  1233.          lsr.l    #5,d0                               ;
  1234.          divu.w   d0,d1                               ;
  1235.          andi.l   #$FFFF,d1                           ;
  1236.          lsr.l    #5,d1                               ;
  1237.          bra.b    30$                                 ;
  1238. 20$      divu.w   d0,d1                               ;
  1239. 30$      move.w   d1,_serper                          ; set period value
  1240. 40$      rts
  1241.          ;
  1242.          ;        Allocate new internal buffer
  1243.          ;
  1244. allocBuf:
  1245.          cmp.l    vb_CurRBufLen(a5),d0                ; len same as previous?
  1246.          beq.b    10$                                 ; yep, so no need to alloc
  1247.          move.l   d0,d1                               ; save length
  1248.          movem.l  d1/a1,-(sp)                         ; save registers
  1249.          moveq    #MEMF_PUBLIC,d1                     ; public memory
  1250.          jsr      _LVOAllocMem(a6)                    ; go allocate it
  1251.          movem.l  (sp)+,d1/a1                         ; restore registers
  1252.          tst.l    d0                                  ; did we get it?
  1253.          beq.b    20$                                 ; if zero, error
  1254.          bsr.b    freeBuf                             ; go free previous buffer
  1255.          move.l   d0,vb_CurRBuf(a5)                   ; store new ptr
  1256.          move.l   d1,vb_CurRBufLen(a5)                ; and length
  1257.          bsr      cmd_Clear                           ; go setup buffer
  1258. 10$      moveq    #0,d0                               ; success
  1259.          rts                                          ; return
  1260. 20$      moveq    #SerErr_BufErr,d0                   ; set error status
  1261.          rts                                          ; return
  1262.          ;
  1263.          ;        Free internal buffer
  1264.          ;
  1265. freeBuf:
  1266.          movem.l  d0-d1/a0-a1,-(sp)                   ; save registers
  1267.          move.l   vb_CurRBuf(a5),d0                   ; is one there?
  1268.          beq.b    10$                                 ; no so branch
  1269.          movea.l  d0,a1                               ; get ptr
  1270.          move.l   vb_CurRBufLen(a5),d0                ; get length
  1271.          clr.l    vb_CurRBuf(a5)                      ; clear
  1272.          clr.l    vb_CurRBufLen(a5)                   ; clear
  1273.          jsr      _LVOFreeMem(a6)                     ; free it
  1274. 10$      movem.l  (sp)+,d0-d1/a0-a1                   ; restore registers
  1275.          rts                                          ; return
  1276.          ;
  1277.          ;        Checks CTS status and if clear generates a TBE interrupt or
  1278.          ;        requeues the timer request.
  1279.          ;
  1280.          ;        Entered from Exec using the MsgPort callback.
  1281.          ;
  1282.          ;        Input:   a6 = ExecBase
  1283.          ;        Output:  none
  1284.          ;
  1285.          ;        No need to preserve d0/d1/a0/a1
  1286.          ;
  1287. timerRtn:
  1288.          lea.l    timerReq(pc),a1                     ; get ptr to timer request
  1289.          jsr      _LVORemove(a6)                      ; remove request
  1290.          ;
  1291.          ;        If we were breaking, reset adkcon.
  1292.          ;
  1293.          btst.b   #ADKB_UARTBRK,_adkconr              ; were we breaking?
  1294.          beq.b    10$                                 ; nope, skip reset
  1295.          ;
  1296.          move.w   #ADKF_UARTBRK,_adkcon               ; stop breaking
  1297.          ;
  1298.          ;
  1299.          ;
  1300. 10$      move.b   Handshake(pc),d0                    ; are we handshaking?
  1301.          beq.b    20$                                 ; nope, generate interrupt
  1302.          btst.b   #CIAB_COMCTS,_ciabpra               ; clear to send?
  1303.          beq.b    20$                                 ; yep, go start writing
  1304.          ;
  1305.          lea.l    timerReq(pc),a1                     ; get ptr to timer request
  1306.          move.l   #1000,IOTV_TIME+TV_MICRO(a1)        ; wait for .001 seconds
  1307.          jsr      _LVOSendIO(a6)                      ; go queue it
  1308.          bra.b    30$                                 ; branch to return
  1309.          ;
  1310.          ;        CTS is clear so generate TBE interrupt to restart writing
  1311.          ;
  1312. 20$      move.w   #INTF_SETCLR|INTF_TBE,_intreq       ; set TBE interrupt
  1313. 30$      rts                                          ; return
  1314.          ;
  1315.          ;        Non serial interrupt
  1316.          ;
  1317. level1n:
  1318.          movem.l  d0-d1/a0-a1/a5-a6,-(sp)             ; save registers
  1319.          lea      _custom,a0                          ; get ptr to custom regs
  1320.          move.w   intenar(a0),d1                      ; get enabled interrupts
  1321.          and.w    intreqr(a0),d1                      ; and in requested interrupts
  1322.          movea.l  SysBase(pc),a6                      ; get ExecBase
  1323.          ;
  1324.          btst     #INTB_DSKBLK,d1                     ; Disk block done?
  1325.          beq.b    10$                                 ; nope, branch
  1326.          ;
  1327.          movem.l  IVDSKBLK(a6),a1/a5                  ; get data and code ptrs
  1328.          pea.l    20$(pc)                             ; push return address
  1329.          jmp      (a5)                                ; jump to routine
  1330.          ;
  1331. 10$      btst     #INTB_SOFTINT,d1                    ; software interrupt?
  1332.          beq.b    20$                                 ; nope, branch
  1333.          ;
  1334.          movem.l  IVSOFTINT(a6),a1/a5                 ; get data and code ptrs
  1335.          pea.l    20$(pc)                             ; push return address
  1336.          jmp      (a5)                                ; jump to routine
  1337.          ;
  1338. 20$      movem.l  (sp)+,d0-d1/a0-a1/a5-a6             ; restore registers
  1339.          rte                                          ; return
  1340.          ;
  1341.          ;        Level 1 interrupt handler
  1342.          ;
  1343. level1:
  1344.          btst.b   #INTB_INTEN,_intenar                ; interrupts enabled?
  1345.          beq.b    35$                                 ; nope, ignore
  1346.          btst.b   #INTB_SOFTINT,_intreqr+1            ; software interrupt?
  1347.          bne.b    level1n                             ; nope, branch
  1348.          btst.b   #INTB_TBE,_intreqr+1                ; xmit buffer empty?
  1349.          beq.b    level1n                             ; nope, invoke old handler
  1350.          ;
  1351.          ;        Handle "Transmit Buffer Empty" interrupt (write)
  1352.          ;
  1353.          move.w   #INTF_TBE,_intreq                   ; clear interrupt
  1354.          move.l   d0,-(sp)                            ; save D0 (faster than MOVEM)
  1355.          move.l   a0,-(sp)                            ; save A0 (faster than MOVEM)
  1356.          ;
  1357.          ;        If we're not handshaking, bypass it.
  1358.          ;
  1359. 10$      move.b   Handshake(pc),d0                    ; are we handshaking?
  1360.          beq.b    20$                                 ; nope, skip CTS test
  1361.          btst.b   #CIAB_COMCTS,_ciabpra               ; clear to send?
  1362.          bne.b    40$                                 ; nope, branch
  1363.          ;
  1364.          ;        If cw_Length goes negative here, we are either done with a
  1365.          ;        request or we were called as a result of a fake interrupt
  1366.          ;        to force us to get the next request going.
  1367.          ;
  1368. 20$      subq.l   #1,cw_Length                        ; decr write length
  1369.          blt.b    60$                                 ; < zero, done, branch
  1370.          ;
  1371.          ;        Currently processing a request.
  1372.          ;
  1373.          movea.l  cw_Buffer(pc),a0                    ; get buffer ptr
  1374.          move.w   #256,d0                             ; set stop bit
  1375.          move.b   (a0)+,d0                            ; get next byte
  1376.          move.l   a0,cw_Buffer                        ; store buffer ptr
  1377.          move.w   d0,_serdat                          ; store in serdat reg
  1378.          ;
  1379. 30$      movea.l  (sp)+,a0                            ; restore registers
  1380.          move.l   (sp)+,d0                            ; restore registers
  1381. 35$      rte                                          ; return
  1382.          ;
  1383.          ;        Queue a timer request to recheck CTS status
  1384.          ;
  1385. 40$      movem.l  d1/a1/a6,-(sp)                      ; save registers
  1386.          lea.l    timerReq(pc),a1                     ; get ptr to timer request
  1387.          move.l   #1000,IOTV_TIME+TV_MICRO(a1)        ; wait for .001 seconds
  1388.          movea.l  SysBase(pc),a6                      ; get ExecBase
  1389.          jsr      _LVOSendIO(a6)                      ; queue the request
  1390.          movem.l  (sp)+,d1/a1/a6                      ; restore registers
  1391.          bra.b    30$                                 ; go return
  1392.          ;
  1393.          ;        There aren't anymore requests, so clear and exit
  1394.          ;
  1395. 50$      clr.l    cw_Length-Start(a6)                 ; clear length
  1396.          clr.l    cw_IOReq-Start(a6)                  ; clear
  1397.          movem.l  (sp)+,d1/a1/a6                      ; restore registers
  1398.          bra.b    30$                                 ; go return
  1399.          ;
  1400.          ;        Write request completed
  1401.          ;
  1402. 60$      movem.l  d1/a1/a6,-(sp)                      ; save registers
  1403.          ;
  1404.          move.l   cw_IOReq(pc),d0                     ; active I/O request?
  1405.          beq.b    70$                                 ; nope, branch
  1406.          ;
  1407.          ;        Reply it and setup for next
  1408.          ;
  1409.          movea.l  d0,a1                               ; get I/O request
  1410.          bclr.b   #IOSERB_ACTIVE,IO_FLAGS(a1)         ; no longer active
  1411.          clr.b    IO_ERROR(a1)                        ; no error
  1412.          movea.l  SysBase(pc),a6                      ; get ExecBase
  1413.          DEBUGIO  replyIO
  1414.          jsr      _LVOReplyMsg(a6)                    ; return I/O request
  1415.          ;
  1416. 70$      lea.l    Start(pc),a6                        ; get section base
  1417.          ;
  1418.          lea.l    writeQ(pc),a1                       ; get ptr to write queue
  1419.          move.l   (a1),a0                             ; get head of list
  1420.          move.l   (a0),d0                             ; get successor
  1421.          beq.b    50$                                 ; end of list? yep, branch
  1422.          ;
  1423.          ;        Remove the node from the list
  1424.          ;
  1425.          move.l   d0,(a1)                             ; make new head
  1426.          exg.l    d0,a0                               ; swap nodes
  1427.          move.l   a1,LN_PRED(a0)                      ; store predecessor
  1428.          ;
  1429.          move.l   d0,a1                               ; get I/O request
  1430.          ;
  1431.          ;        If it's a BREAK, then branch to process as such.
  1432.          ;
  1433.          cmpi.w   #SDCMD_BREAK,IO_COMMAND(a1)         ; BREAK command?
  1434.          beq.b    100$                                ; yep, branch
  1435.          ;
  1436.          ;        Check for absolute length
  1437.          ;
  1438.          move.l   IO_DATA(a1),a0                      ; get data ptr
  1439.          moveq    #-1,d1                              ; get value
  1440.          move.l   IO_LENGTH(a1),d0                    ; get length
  1441.          cmp.l    d1,d0                               ; length = -1?
  1442.          bne.b    90$                                 ; nope, skip scan
  1443.          ;
  1444.          ;        Scan the data for null to calc the length
  1445.          ;
  1446.          move.l   a0,d1                               ; save data ptr
  1447. 80$      tst.b    (a0)+                               ; does it equal 0?
  1448.          bne.b    80$                                 ; nope, so continue
  1449.          suba.l   d1,a0                               ; calc # of bytes+1
  1450.          move.l   a0,d0                               ; xfer
  1451.          subq.l   #1,d0                               ; calc # of bytes
  1452.          movea.l  d1,a0                               ; get data ptr
  1453.          ;
  1454. 90$      move.l   d0,IO_ACTUAL(a1)                    ; go ahead and set it
  1455.          bclr.b   #IOSERB_QUEUED,IO_FLAGS(a1)         ; no longer queued
  1456.          bset.b   #IOSERB_ACTIVE,IO_FLAGS(a1)         ; make it active
  1457.          move.l   d0,cw_Length-Start(a6)              ; store length
  1458.          move.l   a0,cw_Buffer-Start(a6)              ; store buffer ptr
  1459.          move.l   a1,cw_IOReq-Start(a6)               ; store I/O request ptr
  1460.          ;
  1461.          movem.l  (sp)+,d1/a1/a6                      ; restore registers
  1462.          bra      10$                                 ; go start request
  1463.          ;
  1464.          ;        Start the BREAK.
  1465.          ;
  1466. 100$     bclr.b   #IOSERB_QUEUED,IO_FLAGS(a1)         ; no longer queued
  1467.          bset.b   #IOSERB_ACTIVE,IO_FLAGS(a1)         ; make it active
  1468.          clr.l    cw_Length-Start(a6)                 ; clear length
  1469.          move.l   a1,cw_IOReq-Start(a6)               ; store I/O request ptr
  1470.          move.w   #ADKF_SETCLR|ADKF_UARTBRK,_adkcon   ; start break
  1471.          move.l   IO_BRKTIME(a1),d0                   ; get break time
  1472.          lea.l    timerReq(pc),a1                     ; get ptr to timer request
  1473.          move.l   d0,IOTV_TIME+TV_MICRO(a1)           ; set the timeout
  1474.          movea.l  SysBase(pc),a6                      ; get ExecBase
  1475.          jsr      _LVOSendIO(a6)                      ; queue the request
  1476.          movem.l  (sp)+,d1/a1/a6                      ; restore registers
  1477.          bra      30$                                 ; go exit
  1478.          ;
  1479.          ;        Non serial interrupt
  1480.          ;
  1481. level5n:
  1482.          movem.l  d0-d1/a0-a1/a5-a6,-(sp)             ; save registers
  1483.          lea      _custom,a0                          ; get ptr to custom regs
  1484.          move.w   intenar(a0),d1                      ; get enabled interrupts
  1485.          and.w    intreqr(a0),d1                      ; and in requested interrupts
  1486.          movea.l  SysBase(pc),a6                      ; get ExecBase
  1487.          btst     #INTB_DSKSYNC,d1                    ; Disk synchronized?
  1488.          beq.b    10$                                 ; nope, branch
  1489.          movem.l  IVDSKSYNC(A6),a1/a5                 ; get data and code ptrs
  1490.          jsr      (a5)                                ; branch to routine
  1491. 10$      movem.l  (sp)+,d0-d1/a0-a1/a5-a6             ; restore registers
  1492.          rte                                          ; return
  1493.          ;
  1494.          ;        Default Level 5 handler
  1495.          ;
  1496. level5:
  1497.          btst.b   #INTB_INTEN,_intenar                ; interrupts enabled?
  1498.          beq.b    45$                                 ; nope, ignore
  1499.          btst.b   #INTB_RBF,_intreqr                  ; receive buffer full?
  1500.          beq.b    level5n                             ; nope, invoke old handler
  1501.          ;
  1502.          move.l   a0,-(sp)                            ; save registers
  1503.          ;
  1504. 10$      btst.b   #7,_serdatr                         ; Overrun?
  1505.          bne.b    50$                                 ; yep, branch
  1506.          ;
  1507. 20$      movea.l  i_BufIn(pc),a0                      ; get current ptr
  1508.          move.b   _serdatr+1,(a0)+                    ; store received byte
  1509.          move.w   #INTF_RBF,_intreq                   ; clear RBF interrupt
  1510.          addq.l   #1,i_InCnt                          ; incr bytes in buffer
  1511.          ;
  1512.          cmpa.l   i_BufEnd(pc),a0                     ; hit end of buffer?
  1513.          beq.b    60$                                 ; yep, branch
  1514. 30$      move.l   a0,i_BufIn                          ; store input ptr
  1515.          ;
  1516.          subq.l   #1,i_Thresh                         ; close to full buffer?
  1517.          beq.b    70$                                 ; yep, branch
  1518.          ;
  1519. 40$      btst.b   #INTB_RBF,_intreqr                  ; receive buffer full?
  1520.          bne.b    10$                                 ; yep, go get another byte
  1521.          ;
  1522.          movea.l  (sp)+,a0                            ; restore registers
  1523. 45$      rte                                          ; return
  1524.          ;
  1525.          ;        We've missed some data, so set overrun flag.
  1526.          ;
  1527. 50$      addq.b   #1,Overrun                          ; set overrun flag
  1528.          bra.b    20$                                 ; continue
  1529.          ;
  1530.          ;        Hit physical end of buffer, so wrap to the start of the buffer.
  1531.          ;
  1532. 60$      movea.l  i_BufPtr(pc),a0                     ; get buffer ptr
  1533.          bra.b    30$                                 ; continue
  1534.          ;
  1535.          ;        Hit buffer threshold, so tell other end not to send any more
  1536.          ;        data.
  1537.          ;
  1538. 70$      tst.b    Handshake                           ; are we handshaking?
  1539.          beq.b    40$                                 ; nope, skip RTS
  1540.          bset.b   #CIAB_COMRTS,_ciabpra               ; block further input
  1541.          bra.b    40$                                 ; go return
  1542.          ;
  1543.          ;
  1544.          ;
  1545. level2:
  1546.          ;
  1547.          ;        If there's nothing in the buffer, there's no point in going
  1548.          ;        any further.
  1549.          ;
  1550.          move.l   i_InCnt(pc),d0                      ; anything in the buffer?
  1551.          bne.b    20$                                 ; yep, branch
  1552. 10$      moveq    #0,d0                               ; set Z flag
  1553.          rts                                          ; return
  1554.          ;
  1555.          ;        If we've been "disabled" then get out.
  1556.          ;
  1557. 20$      move.b   disableRead(pc),d0                  ; internally disabled?
  1558.          bge.b    10$                                 ; yep, get out of here
  1559.          lea.l    Start(pc),a5                        ; get base
  1560.          ;
  1561.          ;        If we have an active request, branch down and try to fulfill it.
  1562.          ;
  1563.          move.l   cr_IOReq(pc),d0                     ; get and test active I/O
  1564.          bne.b    30$                                 ; nzero, active, branch
  1565.          ;
  1566.          ;        Get first node in list and test if empty.
  1567.          ;
  1568.          move.l   (a1),a0                             ; get head of list
  1569.          move.l   (a0),d0                             ; get successor
  1570.          beq.b    10$                                 ; end of list? yep, branch
  1571.          ;
  1572.          ;        Remove the node from the list
  1573.          ;
  1574.          move.l   d0,(a1)                             ; make new head
  1575.          exg.l    d0,a0                               ; swap nodes
  1576.          move.l   a1,LN_PRED(a0)                      ; store predecessor
  1577.          ;
  1578.          ;        Setup fields for processing a read request
  1579.          ;
  1580.          movea.l  d0,a1                               ; get I/O request
  1581.          bclr.b   #IOSERB_QUEUED,IO_FLAGS(a1)         ; no longer queued
  1582.          bset.b   #IOSERB_ACTIVE,IO_FLAGS(a1)         ; make it active
  1583.          move.l   a1,cr_IOReq-Start(a5)               ; store I/O request
  1584.          move.l   IO_DATA(a1),cr_OutPtr-Start(a5)     ; get/set output ptr
  1585.          move.l   IO_LENGTH(a1),cr_Length-Start(a5)   ; get/set output count
  1586.          ;
  1587.          ;        Process an active I/O request
  1588.          ;
  1589. 30$      movea.l  SysBase(pc),a6                      ; get ExecBase
  1590.          move.l   d0,a1                               ; get I/O request
  1591.          bsr      copyData                            ; go copy 'em
  1592.          tst.l    d0                                  ; done with request?
  1593.          beq.b    10$                                 ; nope, branch
  1594.          ;
  1595.          ;        the request has been satisfied, so return it.
  1596.          ;
  1597.          clr.l    cr_IOReq-Start(a5)                  ; clear request
  1598.          bclr.b   #IOSERB_ACTIVE,IO_FLAGS(a1)         ; no longer active
  1599.          DEBUGIO  replyIO
  1600.          jsr      _LVOReplyMsg(a6)                    ; return I/O
  1601.          bra.b    10$
  1602.          ;
  1603.          ;        Registers:
  1604.          ;        Entry:   A1       Ptr to I/O Request
  1605.          ;                 A6       ExecBase
  1606.          ;        Exit:    D0       ZERO - request not done, do not reply it
  1607.          ;                          NZERO - request done, reply it
  1608.          ;
  1609. copyData:
  1610.          ;
  1611.          ;        Process an active I/O request (or fall through from above)
  1612.          ;
  1613.          movem.l  d2-d5/a1-a5,-(sp)                   ; save registers
  1614.          lea.l    Start(pc),a5                        ; get base
  1615.          movea.l  a1,a4                               ; get I/O request
  1616.          ;
  1617.          movea.l  i_BufOut(pc),a2                     ; get current bufout ptr
  1618.          movea.l  cr_OutPtr(pc),a3                    ; get current output ptr
  1619.          move.l   cr_Length(pc),d2                    ; get current bytes needed
  1620.          move.l   i_InCnt(pc),d3                      ; get current bytes in buffer
  1621.          ;
  1622.          ;        If we don't have enough bytes to satisfy the request,
  1623.          ;        set the length to the number of bytes we do have.
  1624.          ;
  1625.          cmp.l    d2,d3                               ; enuf to satisfy request?
  1626.          bge.b    15$                                 ; yep, so branch
  1627.          move.l   d3,d2                               ; # to copy = # in buffer
  1628.          bra.b    15$                                 ; branch to loop entry
  1629.          ;
  1630.          ;        Start of copy loop.
  1631.          ;
  1632. 10$      movea.l  i_BufPtr(pc),a2                     ; reset bufout to start
  1633.          ;
  1634.          ;        Entry point of copy loop.
  1635.          ;
  1636. 15$      move.l   d2,d3                               ; xfer # of bytes to copy
  1637.          ;
  1638.          ;        If the copy will extend past the end of the buffer, we can
  1639.          ;        only copy the number of bytes to the end this go around.
  1640.          ;
  1641.          move.l   i_BufEnd(pc),d0                     ; get ptr to end of buf
  1642.          sub.l    a2,d0                               ; calc # of bytes to end
  1643.          cmp.l    d0,d3                               ; # to copy < # to end?
  1644.          blt.b    20$                                 ; yep, branch
  1645.          move.l   d0,d3                               ; get bytes to end
  1646.          ;
  1647.          ;        Registers:
  1648.          ;
  1649.          ;        A2 = pointer from which data will be copied
  1650.          ;        A3 = pointer to which data will be copied
  1651.          ;        D2 = number of bytes that need to be copied
  1652.          ;        D3 = number of bytes to copy this iteration
  1653.          ;
  1654. 20$      btst.b   #SERB_EOFMODE,IO_SERFLAGS(a4)       ; EOFMODE requested?
  1655.          beq.b    30$                                 ; nope, just go copy
  1656.          ;
  1657.          ;        EOFMODE was specified so copy characters 1 at a time until
  1658.          ;        we hit an EOF character, the output butter has filled, or
  1659.          ;        the input buffer has drained.
  1660.          ;
  1661.          move.l   d3,d0                               ; get length
  1662.          ;
  1663. 21$      move.b   (a2)+,d1                            ; get byte
  1664.          move.b   d1,(a3)+                            ; put in output buffer
  1665.          ;
  1666.          lea.l    IO_TERMARRAY(a4),a1                 ; get termarry ptr
  1667.          cmp.b    (a1)+,d1                            ; found term char?
  1668.          bge.b    22$                                 ; possibly, branch
  1669.          cmp.b    (a1)+,d1                            ; found term char?
  1670.          bge.b    22$                                 ; possibly, branch
  1671.          cmp.b    (a1)+,d1                            ; found term char?
  1672.          bge.b    22$                                 ; possibly, branch
  1673.          cmp.b    (a1)+,d1                            ; found term char?
  1674.          bge.b    22$                                 ; possibly, branch
  1675.          cmp.b    (a1)+,d1                            ; found term char?
  1676.          bge.b    22$                                 ; possibly, branch
  1677.          cmp.b    (a1)+,d1                            ; found term char?
  1678.          bge.b    22$                                 ; possibly, branch
  1679.          cmp.b    (a1)+,d1                            ; found term char?
  1680.          bge.b    22$                                 ; possibly, branch
  1681.          cmp.b    (a1)+,d1                            ; found term char?
  1682.          bgt.b    23$                                 ; nope, branch
  1683. 22$      beq.b    24$                                 ; term char found?
  1684.          ;
  1685.          ;        Didn't find a term character, so continue with the copy loop
  1686.          ;
  1687. 23$      subq.l   #1,d0                               ; decr length counter
  1688.          bne.b    21$                                 ; continue if more
  1689.          bra.b    40$                                 ; done with copy, branch
  1690.          ;
  1691.          ;        We've found a termination character.
  1692.          ;
  1693. 24$      clr.l    cr_Length-Start(a5)                 ; done with request
  1694.          bra.b    50$                                 ; branch
  1695.          ;
  1696.          ;        EOFMODE not specified, so just do a bulk copy.
  1697.          ;
  1698.          ;        XXX POSSIBLE SPEEDUP XXX
  1699.          ;
  1700.          ;        For short copies it would be quicker to have a simple inline
  1701.          ;        loop, but what's short???  It would be different by CPU.
  1702.          ;
  1703. 30$      move.l   d3,d0                               ; get length
  1704.          movea.l  a3,a1                               ; where to put it
  1705.          movea.l  a2,a0                               ; where to get it
  1706.          jsr      _LVOCopyMem(a6)                     ; copy it
  1707.          adda.l   d3,a2                               ; update bufout
  1708.          adda.l   d3,a3                               ; update outptr
  1709.          ;
  1710.          ;        Fall through and entered from EOFMODE loop
  1711.          ;
  1712.          ;        If the following calculation results in a value greater than
  1713.          ;        zero, then we have a buffer wrap and need to process the
  1714.          ;        remaining bytes at the beginning of the buffer.
  1715.          ;
  1716. 40$      sub.l    d3,d2                               ; calc bytes left to copy
  1717.          bgt      10$                                 ; >0, more to copy, branch
  1718.          ;
  1719.          ;
  1720.          ;
  1721. 50$      move.l   a3,d1                               ; get outptr
  1722.          sub.l    cr_OutPtr(pc),d1                    ; calc length
  1723.          move.l   a3,cr_OutPtr-Start(a5)              ; update outptr
  1724.          ;
  1725.          ;        Update output ptr and I/O request
  1726.          ;
  1727.          move.l   a2,i_BufOut-Start(a5)               ; store bufout ptr
  1728.          add.l    d1,IO_ACTUAL(a4)                    ; update I/O request
  1729.          ;
  1730.          ;        Update number of bytes left in the buffer.
  1731.          ;
  1732.          sub.l    d1,i_InCnt-Start(a5)                ; calc bytes left in buffer
  1733.          ;
  1734.          ;        If the threshold becomes positive here, then, if requested,
  1735.          ;        tell the other end that it's okay to start sending more data.
  1736.          ;
  1737.          add.l    d1,i_Thresh-Start(a5)               ; calc thresh and test
  1738.          ble.b    60$                                 ; <= 0, need more data, skip
  1739.          tst.b    Handshake-Start(a5)                 ; are we handshaking?
  1740.          beq.b    60$                                 ; nope, skip RTS
  1741.          bclr.b   #CIAB_COMRTS,_ciabpra               ; ready to receive more data
  1742.          ;
  1743.          ;        Set error if we've had any overruns.
  1744.          ;
  1745. 60$      tst.b    Overrun-Start(a5)                   ; did overrun occur?
  1746.          beq.b    70$                                 ; nope, branch
  1747.          clr.b    Overrun-Start(a5)                   ; reset overrun flag
  1748.          move.b   #SerErr_LineErr,IO_ERROR(a4)        ; set error code
  1749.          ;
  1750.          ;        Calc number of bytes left to copy.  If the result is greater
  1751.          ;        than zero, then we have more to copy so return an incomplete
  1752.          ;        status.
  1753.          ;
  1754. 70$      moveq    #0,d0                               ; assume I/O incomplete
  1755.          sub.l    d1,cr_Length-Start(a5)              ; update length and test
  1756.          bgt.b    90$                                 ; >0, more to do, branch
  1757.          ;
  1758.          ;        We've completed the I/O request either by copying the requested
  1759.          ;        of bytes or by finding an EOFMODE character, so return a "reply"
  1760.          ;        status.
  1761.          ;
  1762.          moveq    #1,d0                               ; indicate reply
  1763.          ;
  1764.          ;        Restore and exit
  1765.          ;
  1766. 90$      movem.l  (sp)+,d2-d5/a1-a5                   ; restore registers
  1767.          rts                                          ; return (status in D0)
  1768.          ;
  1769.          ;        Align data
  1770.          ;
  1771.          CNOP     0,4
  1772.          ;
  1773.          ;
  1774.          ;
  1775. Init:
  1776.          DC.L     sizeof_Base8n1
  1777.          DC.L     funcTab
  1778.          DC.L     dataTab
  1779.          DC.L     InitRoutine
  1780.          ;
  1781.          ;
  1782.          ;
  1783. funcTab:
  1784.          DC.W     -1
  1785.          DC.W     dev_Open-funcTab
  1786.          DC.W     dev_Close-funcTab
  1787.          DC.W     dev_Expunge-funcTab
  1788.          DC.W     dev_Null-funcTab
  1789.          DC.W     dev_BeginIO-funcTab
  1790.          DC.W     dev_AbortIO-funcTab
  1791.          DC.W     -1
  1792.          ;
  1793.          ;
  1794.          ;
  1795. dataTab:
  1796.          INITBYTE LN_TYPE,NT_DEVICE
  1797.          INITLONG LN_NAME,Name
  1798.          INITBYTE LIB_FLAGS,LIBF_SUMUSED|LIBF_CHANGED
  1799.          INITWORD LIB_VERSION,VERSION
  1800.          INITWORD LIB_REVISION,REVISION
  1801.          INITLONG LIB_IDSTRING,IdString
  1802.          DC.W     0
  1803.          ;
  1804.          ;        String Constants
  1805.          ;
  1806. miscresource:
  1807.          DC.B     "misc.resource",0
  1808. timerdevice:
  1809.          DC.B     "timer.device",0
  1810. intuitlib:
  1811.          DC.B     "intuition.library",0
  1812. Name:
  1813.          DC.B     "8n1.device",0
  1814. IdString:
  1815.          VSTRING
  1816.          ;
  1817.          ;        End of checksummed area.  (Realigns data too!)
  1818.          ;
  1819. ENDTag:
  1820.          CNOP     0,4
  1821.          ;
  1822.          ;        Global SysBase (Use instead of AbsExecBase for speed)
  1823.          ;
  1824. SysBase:
  1825.          DC.L     0
  1826.          ;
  1827.          ;        Internal buffer tracking (DO NOT CHANGE THE ORDER!!!!)
  1828.          ;
  1829. i_BufPtr:
  1830.          DC.L     0
  1831. i_BufIn:
  1832.          DC.L     0
  1833. i_BufOut:
  1834.          DC.L     0
  1835. i_BufEnd:
  1836.          DC.L     0
  1837. i_InCnt:
  1838.          DC.L     0
  1839. i_Thresh:
  1840.          DC.L     0
  1841.          ;
  1842.          ;        Used while processing a read request.
  1843.          ;
  1844. cr_IOReq:
  1845.          DC.L     0
  1846. cr_OutPtr:
  1847.          DC.L     0
  1848. cr_Length:
  1849.          DC.L     0
  1850.          ;
  1851.          ;        List head for read requests
  1852.          ;
  1853. readQ:
  1854.          DC.L     readQ+MLH_TAIL
  1855.          DC.L     0
  1856.          DC.L     readQ
  1857.          ;
  1858.          ;        Write control.
  1859.          ;
  1860. cw_Length:
  1861.          DC.L     0
  1862. cw_Buffer:
  1863.          DC.L     0
  1864. cw_IOReq:
  1865.          DC.L     0
  1866.          ;
  1867.          ;        List head for write requests
  1868.          ;
  1869. writeQ:
  1870.          DC.L     writeQ+MLH_TAIL
  1871.          DC.L     0
  1872.          DC.L     writeQ
  1873.          ;
  1874.          ;
  1875.          ;
  1876. timerPort:
  1877.          DC.L     0                                   ; LN_SUCC
  1878.          DC.L     0                                   ; LN_PRED
  1879.          DC.B     NT_MSGPORT                          ; LN_TYPE
  1880.          DC.B     0                                   ; LN_PRI
  1881.          DC.L     0                                   ; LN_NAME
  1882.          DC.B     3                                   ; MP_FLAGS (undoc'ed)
  1883.          DC.B     0                                   ; MP_SIGBIT
  1884.          DC.L     timerRtn                            ; MP_SIGTASK
  1885.          DC.L     timerPort+MP_MSGLIST+LH_TAIL        ; LH_HEAD
  1886.          DC.L     0                                   ; LH_TAIL
  1887.          DC.L     timerPort+MP_MSGLIST                ; LH_TAILPRED
  1888.          DC.B     0                                   ; LH_TYPE
  1889.          DC.B     0                                   ; LH_pad
  1890.          DC.W     0                                   ; long align
  1891.          ;
  1892.          ;
  1893.          ;
  1894. timerReq:
  1895.          DC.L     0                                   ; LN_SUCC
  1896.          DC.L     0                                   ; LN_PRED
  1897.          DC.B     NT_MESSAGE                          ; LN_TYPE
  1898.          DC.B     0                                   ; LN_PRI
  1899.          DC.L     0                                   ; LN_NAME
  1900.          DC.L     timerPort                           ; MN_REPLYPORT
  1901.          DC.W     IOTV_SIZE                           ; MN_LENGTH
  1902.          DC.L     0                                   ; IO_DEVICE
  1903.          DC.L     0                                   ; IO_UNIT
  1904.          DC.W     TR_ADDREQUEST                       ; IO_COMMAND
  1905.          DC.B     0                                   ; IO_FLAGS
  1906.          DC.B     0                                   ; IO_ERROR
  1907.          DC.L     0                                   ; TV_SECS
  1908.          DC.L     0                                   ; TV_MICROS
  1909.          ;
  1910.          ;
  1911.          ;
  1912. VBInterrupt:
  1913.          DC.L     0                                   ; LN_SUCC
  1914.          DC.L     0                                   ; LN_PRED
  1915.          DC.B     NT_INTERRUPT                        ; LN_TYPE
  1916.          DC.B     0                                   ; LN_PRI
  1917.          DC.L     Name                                ; LN_NAME
  1918.          DC.L     readQ                               ; IS_DATA
  1919.          DC.L     level2                              ; IS_CODE
  1920.          ;
  1921.          ;        Global flags
  1922.          ;
  1923. Overrun:
  1924.          DC.B     0
  1925. Handshake:
  1926.          DC.B     1
  1927. disableRead:
  1928.          DC.B     -1
  1929.          ;
  1930.          ;
  1931.          ;
  1932.          END
  1933.  
  1934.